#pragma once
#include <unistd.h>
#include <iostream>
#include"Util.hpp"
#include<string>
#include<string.h>
#include<vector>
#include"log.hpp"
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sstream>
#include<unordered_map>
#include<sys/sendfile.h>
#include <fcntl.h>
#include<sys/wait.h>
using namespace std;

#define OK 200
#define NOT_FOUND 404
#define WEB_ROOT "wwwroot"
#define HOME_PAGE "index.html"
#define HTTP_VERSION "HTTP/1.0"
#define LINE_END "\r\n"
#define ERROR_PAGE "wwwroot/error.html"

static string Code2Desc(int code){

    string desc;
    switch(code){
        case 200:
        desc="OK";break;
        case 404:
        desc="NOT FOUNT";break;

        default:
        break;
    }

    return desc;
}


static string suffix2Desc(string suffix){

    static unordered_map<string,string> suffix2desc={
        {".html","text/html"},
        {".txt","text/plain"},
        {".jpg","image/jpeg"},
        {".png","image/png"},
        {".json","application/json"},
        {".xml","application/xml"},
        {".out","application/octet-stream"}
        
    };

    auto iter=suffix2desc.find(suffix);
    if(iter!=suffix2desc.end()){
        return iter->second;
    }

    return "text/html";

}

class HttpRequest{
public:
    string request_line;
    vector<string> request_header;
    string blank;
    string request_body;
    
    //解析之后的结果
    string method;
    string uri;
    string version;

    unordered_map<string,string> header_kv;
    int content_length=0;
    string path=WEB_ROOT;
    string query_string;
    

    bool cgi=false;

};

//读取请求，分析请求，构筑响应
class HttpResponse{
public:
    string respone_line;
    vector<string> respone_header;
    string blank=LINE_END;
    string respone_body;

    int status_code=OK;
    int fd=-1;
    int size;
  
    string suffix;
    string response_type;
    
};


class Endpoint{

private:
    int _sock;
    HttpRequest _req;
    HttpResponse _res;

public:
    Endpoint(int sock)
    :_sock(sock)
    {}

    void RcvHttpRequest(){
        RecvHttpRequestLine();
        RecvHttpRequestHander();
        ParseHttpRequestLine();
        ParseHttpRequestHander();
        RecvHttpRequestBody();
    }

 

    void BuildHttpResponse(){

        if(_req.method!="GET"&&_req.method!="POST"){
            //非法请求
            
            auto&code=_res.status_code;
            LOG(WARNING,"method is error");
            code=NOT_FOUND;

            return;
        }

        if(_req.method=="GET"){
            
            ssize_t pos=_req.uri.find('?');
            if(pos!=string::npos){
                auto tmp=_req.uri;
                cout<<"tmp:"<<tmp<<endl;
                string sub1=tmp.substr(0,pos);
                string sub2=tmp.substr(pos+1);
                _req.path+=sub1;
                _req.query_string=sub2;

                _req.cgi=true;
            }
            else{
                _req.path+=_req.uri;
            }
            //printf("uri:%s\npath:%s\nquery:%s\n",_req.uri.c_str(),_req.path.c_str(),_req.query_string.c_str());
        }
        else{
            //POST
            _req.path+=_req.uri;
            _req.cgi=true;
        }

        if(_req.path=="wwwroot/"){
            _req.path+=HOME_PAGE;
        }

         struct stat st;
         int size=0;
         cout<<_req.path<<endl;


         if(stat(_req.path.c_str(),&st)==0){
            //资源存在
            if(S_ISDIR(st.st_mode)){
                //请求资源是一个目录
                _req.path+="/index.html";
                stat(_req.path.c_str(),&st);
            }
            if(S_ISREG(st.st_mode) && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))){
                //可执行文件
                _req.cgi=true;
            }
            size=st.st_size;//获取资源的大小
            
         }
         else{
            //资源不存在
            LOG(WARNING,"访问资源不存在");
            // _res.status_code=NOT_FOUND;
            _req.path="wwwroot/404.html";
            stat(_req.path.c_str(),&st);
            
            size=st.st_size;
         }

         //查找后缀
         int pos1=_req.path.rfind('.');
         _res.suffix=_req.path.substr(pos1);

         _res.response_type=suffix2Desc(_res.suffix);

         if(_res.suffix==".html"){
            _req.cgi=false;
         }


         if(_req.cgi){
            //processCgi
            _res.status_code=ProcessCgi();
         }
         else{

            cout<<_req.path<<endl;
            _res.status_code=processNonCgi(size);
         }

         if(_res.status_code!=OK){
            BuildHttpResponseHelper(_res.status_code);
         }
    }

    void SendHttpResponse(){
        

        send(_sock,_res.respone_line.c_str(),_res.respone_line.size(),0);
        
        
        for(auto i:_res.respone_header){
            send(_sock,i.c_str(),i.size(),0);
            send(_sock,LINE_END,2,0);
        }
        send(_sock,LINE_END,2,0);

        sendfile(_sock,_res.fd,nullptr,_res.size);

        close(_res.fd);
    }

    ~Endpoint(){}

private:
    void RecvHttpRequestLine(){
        Util::ReadLine(_sock,_req.request_line);
        LOG(INFO,_req.request_line);
    }

    void RecvHttpRequestHander(){
        
        string line;
        cout<<"开始读取请求头"<<endl;
        while(1){
            line.clear();
            Util::ReadLine(_sock,line);
            //line.resize(line.size()-1);
            if(line=="\n")
            break;
            LOG(INFO,line);
            _req.request_header.push_back(line);
            
            
            
        }
        cout<<"http请求头读取完毕"<<endl;
        if(line=="\n")_req.blank="\n";

        cout<<"读取行结束"<<endl;
    }

    void ParseHttpRequestLine(){

        string &line=_req.request_line;
        
        stringstream ss(line);

        ss>>_req.method>>_req.uri>>_req.version;

        //cout<<"uri:"<<_req.uri<<endl;

    }

    void ParseHttpRequestHander(){
        
        for(auto i:_req.request_header){
            int pos=i.find(':');
            string key=i.substr(0,pos);
            string value=i.substr(pos+2);

            _req.header_kv[key]=value;
        }

        // for(auto i: _req.header_kv){
        //     cout<<"请求头里有："<<i.first<<"->"<<i.second<<endl;
        // }
    }

    bool IsRecvHttpRequestBody(){
        string & method=_req.method;
        if(method=="POST"){
            auto &header_kv=_req.header_kv;
            auto iter=header_kv.find("Content-Length");
            if(iter!=header_kv.end()){
                _req.content_length=stoi(iter->second);
                cout<<"有请求体,返回1"<<endl;
                return true;
            }
        }
        cout<<"无请求体,返回0"<<endl;
        return false;
    }

    void RecvHttpRequestBody(){
        if(IsRecvHttpRequestBody()){
            int content_length=_req.content_length;
            string &body=_req.request_body;

            char ch=0;

            while(content_length--){
                ssize_t n=recv(_sock,&ch,1,0);
                if(n>0){
                    body+=ch;
                }
                else{break;}
            }

            cout<<body<<endl;
        }
    }


    int processNonCgi(int size){
        cout<<"processNonCgi启动"<<endl;
        _res.fd=open(_req.path.c_str(),O_RDONLY);
        if(_res.fd>=0){

            _res.respone_line=HTTP_VERSION;
            _res.respone_line+=" ";
            _res.respone_line+=to_string(_res.status_code);
            _res.respone_line+=" ";
            _res.respone_line+=Code2Desc(_res.status_code);
            _res.respone_line+=LINE_END;

            string content_length_str="Content-Length:";
            content_length_str+=to_string(size);

            string content_type_str="Content-Type:";
            content_type_str+=_res.response_type;
            _res.respone_header.push_back(content_length_str);
            _res.respone_header.push_back(content_type_str);

            _res.size=size;

            return OK;

        }
        else{
            LOG(FATAL,"open resource failed");
            return NOT_FOUND;
        }
        
    }


    int ProcessCgi(){
        cout<<"使用cgi模式"<<endl;
        string& bin=_req.path;

        // string & query_string=_req.query_string;
        // string &body_text=_req.request_body;

        string query_string_env;
        string method_env;
        string content_length;

        int input[2];
        int output[2];//站在父进程角度

        if(pipe(input)<0){
            
            LOG(ERROR,"input pipe fail");
            return 404;
        }

        if(pipe(output)<0){
            
            LOG(ERROR,"output pipe fail");
            return 404;
        }

        pid_t pid=fork();

        if(pid==0){
            //子进程
            close(input[0]);
            close(output[1]);


            dup2(output[0],0);
            dup2(input[1],1);

            method_env="METHOD=";
            method_env+=_req.method;
            
            putenv(strdup(method_env.c_str()));
            if(_req.method=="GET"){
                query_string_env="QUERY_STRING=";
                query_string_env+=_req.query_string;
                putenv(strdup(query_string_env.c_str()));//环境变量传递信息


            }

            if(_req.method=="POST"){
                content_length="Content-Length=";
                content_length+=to_string(_req.content_length);
                putenv(strdup(content_length.c_str()));
                
            }

            execl(bin.c_str(),bin.c_str(),nullptr);
            exit(1);

        }

        else if(pid<0){
            LOG(WARNING,"fork failed");
            return 404;
        }

        else{
            //父进程
            close(input[1]);
            close(output[0]);

            if(_req.method=="POST"){

                
                const char *start=_req.request_body.c_str();
                int total=0;
                int size=0;

                while((size=write(output[1],start+total,_req.request_body.size()-total))>0){
                    total+=size;    
                }
            }       

            char ch;
            while(read(input[0],&ch,1)>0){
                _res.respone_body.push_back(ch);
            }

            int status=0;
            pid_t ret=waitpid(pid,&status,0);
            if(ret==pid){
                if(WIFEXITED(status)){
                    if(WEXITSTATUS(status)==0){
                        //

                        _res.status_code= OK;
                    }
                    _res.status_code=404;
                }
                else{
                    _res.status_code= 404;
                }
            }

            close(input[0]);
            close(output[1]);
        }

        return _res.status_code;
    }

    void HandlerNotFound(){
        _res.fd=open(ERROR_PAGE,O_RDONLY);

        if(_res.fd>0){
            struct stat st;
            stat(ERROR_PAGE,&st);
            string line="Content-Type:text/html";
            line+=LINE_END;
            _res.respone_header.push_back(line);

            line="Content Length:";
            line+=to_string(st.st_size);
            line+=LINE_END;
            _res.respone_header.push_back(line);   


        }
    }

    void BuildHttpResponseHelper(int code){
        _res.respone_line+=HTTP_VERSION;
        _res.respone_line+=" ";
        _res.respone_line+=to_string(code);
        _res.respone_line+=Code2Desc(code);

        switch(code){
            case 404:
                HandlerNotFound();
        }
    }

};
    


class CallBack
{

public:
    static void *HandlerRequset(int sock)
    {
        LOG(INFO,"Handler request start");
        
 

        cout << "获得了一个链接:" << sock << endl;
// #ifndef DEBUG
// #define DEBUG
//         char buffer[1024 * 10] = {0};
//         int n = read(sock, buffer, sizeof(buffer));
//         if (n > 0)
//         {
//             buffer[n] = '\0';

//             cout << buffer << endl;
//         }
// #endif
        // string line;
        // cout<<"开始读行"<<endl;
        // Util::ReadLine(sock,line);  
        // cout<<line<<endl;   
        // close(sock);
        // return nullptr;


        Endpoint *ep=new Endpoint(sock);
        ep->RcvHttpRequest();
        ep->BuildHttpResponse();
        ep->SendHttpResponse();

        cout<<"一次请求响应结束"<<endl;
        cout<<"-----------------------------"<<endl;

        delete ep;
        close(sock);

        return nullptr;
    }


    void operator()(int sock){
        HandlerRequset(sock);
    }
};